#!/usr/bin/python

"""
 Module: gettags.py
  Ver: 2.1; Rev Last: 08/29/2012 - Previous: 08/28/2012

 Rev 2.0; Last: 01/18/2012 - Previous: 12/26/2011 (AEM)
   - Minor bug fixes
   - Add cfg file values

 Rev 2.1; Last: 08/29/2012 - Previous: 08/28/2012  (AEM)
   - Add runtime logging
   - Remove remaining (almost) debug code
   - Add artist name to save function

 Rev 2.2.1; Last: 02/12/2013 - Previous: 02/11/2013  (AEM)
   - Clean up to match PEP8 style guide as closely as practical
   - Clean up to match pylint style guide as closely as practical

 Functions to extract tag data from MP3 files.

 Function get_Mp3_stream_tags(MusicPath)
   - Input: Full file path and file name of the *.mp3 file.
   - Output: Returns file/song statistics in key/value dictionary.

 Function get_mp3_name_tags(MusicPath)
   - Input: Full file path and file name of the *.mp3 file.
   - Output: Returns track/artist tag info in key/value dictionary.

 Valid file path checking will be left to the calling module.

 Dependencies:
     - Install mutagen library. See opening comments in showtags.py
       for instructions.

 Copyright (C) 2010-2012  Arnold E. Morgan

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see http://www.gnu.org/licenses/.

"""

import os
import os.path
import sys
import stat                   # Index constants for os.stat()
import time                   # Format date/time of file stats
from mutagen.id3 import ID3, TALB, TCON, TDRC, TIT2, TDRL, TPE1
from mutagen.mp3 import MP3
import logging


def get_mp3_stream_tags(MusicPath):
   """ Gets mostly file related data items.

   Ask mutagen to pull out all analytic MP3 related tag info.
   We`ll parse out the parts we need. In addition, save file
   size and date/time related characteristics.

   Input: Path to the MP3 file
   Output: Dictionary of key/value pairs
   """

   MP3Tags = {}    # Dictionary to return values
   FailFlag = False

   try:
      audio1 = MP3(MusicPath)
   except (IOError, OSError), e:
      #*** MSSG LEVEL CRITICAL ***
      FailFlag = True
      logging.error('Read Stream Tags Error processing "%s": %s. ' %
                    (MusicPath, e))

   if not FailFlag:
      #logging.info('Read MP3 Stream Tags Successful')

      FileStats = os.stat(MusicPath)
      FSize = FileStats[stat.ST_SIZE]
      if FSize > 1000000:
         strFSize = str("%3.2f" % (FSize / 1000000.0)) + " M"
      else:
         strFSize = str("%3.2f" % (FSize / 1000.0)) + " K"

      MP3Tags['filesize'] = strFSize
      MP3Tags['lastmod'] = time.strftime("%m/%d/%Y %I:%M:%S %p",
                                     time.localtime(FileStats[stat.ST_MTIME]))
      MP3Tags['lastaccess'] = time.strftime("%m/%d/%Y %I:%M:%S %p",
                                     time.localtime(FileStats[stat.ST_ATIME]))
      MP3Tags['created'] = time.strftime("%m/%d/%Y %I:%M:%S %p",
                                     time.localtime(FileStats[stat.ST_CTIME]))

      TotalLenSecs = audio1.info.length
      decMins = TotalLenSecs / 60.0
      intMins = int(decMins)
      intSecs = int((decMins - intMins) * 60)
      TrackLen = "%02d:%02d" % (intMins, intSecs)
      MP3Tags['length'] = TrackLen

      #logging.debug("TotalLenSecs: %s, decMins: %s, intMins: %s, " \
      #               "intSecs: %s, TrackLen: %s" \
      #  % (TotalLenSecs, decMins, intMins, intSecs, TrackLen))

      intBitRate = audio1.info.bitrate
      strBitRate = str("%3.1f" % (intBitRate / 1000.0)) + " Kbps"
      MP3Tags['bitrate'] = strBitRate

      #logging.debug("int BitRate: %s, str BitRate: %s" % \
      #              (intBitRate, strBitRate))

      intSampleRate = audio1.info.sample_rate
      strSampleRate = str("%3.1f" % (intSampleRate / 1000.0)) + " Khz"
      MP3Tags['samplerate'] = strSampleRate

      MP3Tags['layer'] = audio1.info.layer

      #     Mode:
      #     0 = Stereo
      #     1 = JointStereo
      #     2 = Dual Channel
      #     3 = Mono
      MP3Tags['mode'] = audio1.info.mode

      MP3Tags['padding'] = audio1.info.padding
      MP3Tags['protected'] = audio1.info.protected
      MP3Tags['sketchy'] = audio1.info.sketchy

      MP3Tags['filename'] = os.path.basename(MusicPath)
      MP3Tags['version'] = audio1.info.version

   return MP3Tags


def get_mp3_name_tags(MusicPath):
   """ Gets mostly track/artist related data items.

   Ask mutagen to pull out relevant song/album MP3 related tag info.
   We`ll parse out the parts we need.

   Input: Path to MP3 file
   Output: Dictionary of relevant tag data

   """

   MP3RawTags = {}    # Function local working dictionary
   MP3NameTags = {}   # Tag dictionary returned to caller
   FailFlag = False

   # Pull all included tag data; only tags of interest will be returned
   try:
      MP3Info = MP3(MusicPath)
      AllKeys = MP3Info.keys()
      for TagKey in AllKeys:
         MP3RawTags[TagKey] = MP3Info.get(TagKey)
   except (IOError, OSError), e:
      # MSSG LEVEL CRITICAL
      FailFlag = True
      logging.error('Read Name Tags Error processing "%s": %s. ' %
                    (MusicPath, e))

   if not FailFlag:
      # Populate the return tag dictionary with human names for easier
      # tag identification by the caller.
      # logging.info('Read MP3 Name Tags Successful')

      MP3NameTags['albumname'] = MP3RawTags.get('TALB', 'unknown')
      MP3NameTags['contenttype'] = MP3RawTags.get('TCON', 'unknown')
      MP3NameTags['songtitle'] = MP3RawTags.get('TIT2', 'unknown')
      MP3NameTags['artist'] = MP3RawTags.get('TPE1', 'unknown')
      MP3NameTags['radiostation'] = MP3RawTags.get('TRSN', 'unknown')
      MP3NameTags['track'] = MP3RawTags.get('TRCK', 0)
      MP3NameTags['comments'] = MP3RawTags.get("COMM::'eng'", 'unknown')
      MP3NameTags['encodedby'] = MP3RawTags.get('TENC', 'unknown')
      MP3NameTags['subtitle'] = MP3RawTags.get("TIT3", 'unknown')
      MP3NameTags['releasetime'] = MP3RawTags.get('TDRL', 'unknown')
      MP3NameTags['year'] = MP3RawTags.get('TDRC', 'unknown')
      #MP3NameTags['year'] = MP3RawTags.get('TORY', 'unknown')
      #MP3NameTags['picture'] = MP3RawTags.get('APIC:', '') *** future ***

   return MP3NameTags


def save_my_tags(theFilePath, theTitle, theAlbum, theArtist, theYear,
                 theDate, theContentType):
   """
       Save tag values back to the MP3 file.
       But only save a value if its len > 0
       Also strip whitespace before saving.
   """

   theErrState = "Save Ok"
   FailFlag = False
   theTags = ID3(theFilePath)

   if len(theAlbum) > 0:
      theTags['TALB'] = TALB(3, theAlbum.strip())

   if len(theArtist) > 0:
      theTags['TPE1'] = TPE1(3, theArtist.strip())

   if len(theContentType) > 0:
      theTags['TCON'] = TCON(3, theContentType.strip())

   if len(theYear) > 0:
      theTags['TDRC'] = TDRC(3, theYear.strip())

   if len(theDate) > 0:
      theTags['TDRL'] = TDRL(3, theDate.strip())

   if len(theTitle) > 0:
      theTags['TIT2'] = TIT2(3, theTitle.strip())

   try:
      theTags.save()
   except (IOError, OSError), e:
      FailFlag = True
      theErrState = 'Save Tags Error: %s.' % (e)
      logging.error(theErrState)
   except:
      FailFlag = True
      theErrState = "Unexpected Save Tag Error: ", sys.exc_info()[0]
      logging.error(theErrState)

   #logging.debug("Tags: %s" % theTags)
   if not FailFlag:
      logging.info(theErrState)
   return theErrState


if __name__ == "__main__":
   # This is all debug, test stuff ***
   filepath = r"/Utility1/Music/CRock/Aerosmith_DreamOn.mp3"
   #filepath = r"/Utility1/Music/CRock/Aerosmith_AdamsApple.mp3"
   #filepath = r"/media/panther/Audio/TechGuy/ttg0661.mp3"
   #filepath = r"/media/panther/Audio/SecurityNow/SN-041.mp3"

   # Does filepath exist?  Is it a file, or a directory?
   print "Path: %s" % filepath
   print "File exists: %s" % os.path.exists(filepath)
   print "Is a file: %s" % os.path.isfile(filepath)
   print "Is a directory: %s" % os.path.isdir(filepath)
   print "**********************************"

   myMP3 = get_mp3_stream_tags(filepath)

   #print "Stream Tags:\n %s" % myMP3
   for StreamKey in myMP3.keys():
      if StreamKey == "picture":
         print "%s - picture present" % StreamKey
      else:
         print "%s - %s" % (StreamKey, myMP3[StreamKey])

   myFileMP3 = get_mp3_name_tags(filepath)

   print "----------- MP3 -----------------------"
   print myMP3
   print "---------------------------------------"

   for mp3tag in myFileMP3.keys():
      print mp3tag, '\t', myFileMP3[mp3tag]
   print "**********************************"
